
#include "model.h"
#include<QFile>
#include <qdebug.h>

//Model::Model(QObject *parent) : QObject(parent)
//{

//}

Model::Model(const QString &path)
{
    this->initializeOpenGLFunctions();
    loadModel(path);
}

Model::~Model()
{
//    for(int i=0;i<meshes.size();i++)
//        delete meshes[i];
//    for(int i=0;i<gltextures.size();i++)
//        delete gltextures[i];
}

void Model::loadModel(const QString& path)
{
    Assimp::Importer importer;
    const aiScene *scene=importer.ReadFile(path.toLatin1(),aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
    //const aiScene *scene=importer.ReadFile(path.toLatin1(),aiProcess_Triangulate | aiProcess_FlipUVs);
    if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
    {
        qDebug() << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl;
        return;
    }
    int index=path.lastIndexOf('/');
    directory=path.left(index);
    processNode(scene->mRootNode,scene);
    //processMaterials(scene);

}
void Model::processNode(aiNode *node,const aiScene *scene)
{
    for(unsigned int i=0;i<node->mNumMeshes;i++)
    {
        aiMesh* mesh=scene->mMeshes[node->mMeshes[i]];
        meshes.push_back(processMesh(mesh, scene));
    }
    for(unsigned int i=0;i<node->mNumChildren;i++)
    {
        processNode(node->mChildren[i],scene);
    }
}
Mesh* Model::processMesh(aiMesh *mesh, const aiScene *scene)
{
    QVector<Vertex> vertices;
    QVector<unsigned int> indices;
    QVector<Texture> textures;

    // walk through each of the mesh's vertices
    for(unsigned int i = 0; i < mesh->mNumVertices; i++)
    {
        Vertex vertex;
        QVector3D vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.
        // positions
        vector.setX(mesh->mVertices[i].x);
        vector.setY(mesh->mVertices[i].y);
        vector.setZ(mesh->mVertices[i].z);
        vertex.Position = vector;

        vector.setX(mesh->mNormals[i].x);
        vector.setY(mesh->mNormals[i].y);
        vector.setZ(mesh->mNormals[i].z);
        vertex.Normal = vector;

        if(mesh->mTextureCoords[0]) // 网格是否有纹理坐标？
        {
            QVector2D vec;
            vec.setX( mesh->mTextureCoords[0][i].x);
            vec.setY( mesh->mTextureCoords[0][i].y);
            vertex.TexCoords = vec;
        }
        else
            vertex.TexCoords ={ 0.0f, 0.0f};
        vertices.push_back(vertex);
    }

    // 面索引
    qDebug()<<"mNumFaces="<<mesh->mNumFaces;
    // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
    for(unsigned int i = 0; i < mesh->mNumFaces; i++)
    {
        aiFace face = mesh->mFaces[i];
        // retrieve all indices of the face and store them in the indices vector
        for(unsigned int j = 0; j < face.mNumIndices; j++)
            indices.push_back(face.mIndices[j]);
    }

    // 材质
    if(mesh->mMaterialIndex >= 0)
    {
        aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
        QVector<Texture> diffuseMaps = loadMaterialTextures(material,
                                            aiTextureType_DIFFUSE, "texture_diffuse");

        for(auto &t:diffuseMaps) textures.append(t);

        QVector<Texture> specularMaps = loadMaterialTextures(material,
                                            aiTextureType_SPECULAR, "texture_specular");

        for(auto &t:specularMaps) textures.append(t);


        QVector<Texture> hightMaps = loadMaterialTextures(material,
                                            aiTextureType_HEIGHT, "texture_specular");

        for(auto &t:hightMaps) textures.append(t);

    }
    QString qs = QString("v: %1, index: %2, text: %3").arg(vertices.size())
            .arg(indices.size())
            .arg(textures.size());
    qDebug()<< qs;
    return new Mesh(vertices, indices, textures);
}


unsigned int TextureFromFile(const char *path, const QString &directory, bool gamma=false)
{
//    QString filename = QString("%1/%2").arg(directory).arg(path);

//    unsigned int textureID;
//    glGenTextures(1, &textureID);



//    texture1 = new QOpenGLTexture(QImage(":/image/images/wall.jpg"));
//    texture1->setWrapMode(QOpenGLTexture::Repeat);
//    texture1->setMinificationFilter(QOpenGLTexture::Nearest);
//    texture1->setMagnificationFilter(QOpenGLTexture::Linear);


//    int width, height, nrComponents;
//    unsigned char *data = stbi_load(filename.toUtf8().data(), &width, &height, &nrComponents, 0);
//    if (data)
//    {
//        GLenum format;
//        if (nrComponents == 1)
//            format = GL_RED;
//        else if (nrComponents == 3)
//            format = GL_RGB;
//        else if (nrComponents == 4)
//            format = GL_RGBA;

//        glBindTexture(GL_TEXTURE_2D, textureID);
//        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
//        glGenerateMipmap(GL_TEXTURE_2D);

//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//        stbi_image_free(data);
//    }
//    else
//    {
//        std::cout << "Texture failed to load at path: " << path << std::endl;
//        stbi_image_free(data);
//    }

//    return textureID;
    return 0;
}

QVector<Texture> Model::loadMaterialTextures(aiMaterial *mat, aiTextureType type, QString typeName)
{
    QVector<Texture> textures;
    for(unsigned int i = 0; i < mat->GetTextureCount(type); i++)
    {
        aiString str;
        mat->GetTexture(type, i, &str);
        bool skip = false;
        for(unsigned int j = 0; j < textures_loaded.size(); j++)
        {
            if(std::strcmp(textures_loaded[j].path.toUtf8().data(), str.C_Str()) == 0)
            {
                textures.push_back(textures_loaded[j]);
                skip = true;
                break;
            }
        }
        if(!skip)
        {   // 如果纹理还没有被加载，则加载它
            Texture texture;
            texture.id = TextureFromFile(str.C_Str(), directory);
            texture.type = typeName;
            texture.path = QString("%1/%2").arg(directory).arg(str.C_Str());
            qDebug()<<"tex: "<< texture.path<< type;
            textures.push_back(texture);
        }
    }
    return textures;
}


void Model::Draw(QOpenGLShaderProgram &shader)
{
    for(unsigned int i = 0; i < meshes.size(); i++)
        meshes[i]->Draw(shader);
}
